<?php
/*
 * Implements a state machine that represents a reservation creation process
 * that is distributed across multiple HTTP-requests.
 * The conversation's state is persisted in the active session across requests.
 */
class ReservationConversation {
	
	// CLASS --------------------------------------------->
	const ACTIVE = "CONVERSATION_RESERVATION";
	
	/*
	 * Attempts to load currently active conversation, if none is found
	 * a new one is started
	 */
	public static function getCurrent() {
		if (self::exists()) {
			$res = $_SESSION[self::ACTIVE];
			return new ReservationConversation($res);
		} else {
			return new ReservationConversation(new Reservation());
		}
	}
	/*
	 * Determins whether a conversation is currently active
	 */
	public static function exists() {
		return isset($_SESSION[self::ACTIVE]);	
	}
	
	// MEMBER -------------------------------------------->
	// reservation instance
	private $active;
	
	public function __construct(Reservation $res) {
		$this->active = $res->reloadReferences();
		$this->persist();
		return $this;
	}

	public function getReservation() {
		return $this->active;
	}
	
	public function __toString() {
		return $this->active->__toString();
	}
	
	// Sets the customer that owns the reservation
	public function owner(Customer $customer) {
		$this->active->setCustomer($customer);
		try {
			$this->active->checkAge(); 
		} catch (DomainException $e) {
			// ok, reservation is not complete
		}
		$this->persist();
		return $this;
	}
	
	// Sets station where car is picked up and dropped
	// drop off may be omitted --> equals pick up
	public function stations($pickup,$dropoff = null) {
		if (!isset($dropoff)) {
			$dropoff = $pickup;
		}
		$this->active->setStationRelatedByPickup($pickup);
		$this->active->setStationRelatedByDropoff($dropoff);
		$valid = false;
		try {
			$this->active->checkStationCategories();
		} catch (DomainException $e) {
			// ok, reservation is not complete
		}
		$this->persist();
		return $this;
	}
	
	// sets car category
	public function category($category) {
		$this->active->setCategory($category);
		try {
			$this->active->checkAge();
			$this->active->checkStationCategories();
		} catch (DomainException $e) {
			// ok, reservation is not complete
		}
		$this->persist();
		return $this;
	}
	
	// sets start/end times
	public function range($start,$ends) {
		$this->active->setStarts($start);
		$this->active->setEnds($ends);
		$this->active->checkTimes();
		$this->persist();
		return $this;
	}
	
	// checks validity of set values and persists reservation to database
	// true if validation succeeded, error string else
	public function finish() {
		$valid = false;
		$res = $this->active;
		if ($res->isValid()) {
			$res->place();
			$valid = $res->calculatePrice();
		}
		if ($valid) {
			// save to db
			$res->save();
			// clear conversation in session
			unset($_SESSION[self::ACTIVE]); 
		} else {
			throw new DomainException("cannot finish invalid reservation", 400);
		}
	}
	
	// discards this conversation
	public function terminate() {
		unset($_SESSION[self::ACTIVE]);
		$this->active = new Reservation();
		$this->persist();
		return $this;
	}
	
	// stores current state in session, overwriting existing conversation
	protected function persist() {
		$_SESSION[self::ACTIVE] = $this->active;
	}
}
?>